package pfctrller;

import java.util.List;

public class Pipe {
	private Device src;
	private Device dst;
	private Link[] links;
	private long[] availableLinkBw;
	private long aggregateBw;
	private long availableAggregateBw;

	public Pipe(Device src, Device dst, Port[] from, Port[] to){
		this.src = src;
		this.dst = dst;
		this.links = new Link[from.length];
		for(int i = 0; i < links.length; i++){
			links[i] = new Link(from[i], to[i],
					Math.min(src.getTransmissionRate(), dst.getTransmissionRate()));
		}
		// aggregate BW
		this.aggregateBw = 0;
		for(int i = 0; i < links.length; i++){
			this.aggregateBw += links[i].getRateLimit();
		}
		availableAggregateBw = this.aggregateBw;
		
		// init the bw bookkeeping
		availableLinkBw = new long[links.length];
		for(int i = 0; i < availableLinkBw.length; i++){
			availableLinkBw[i] = links[i].getRateLimit();
		}
	}
	
	//
	// Getter and Setters
	//
	
	/**
	 * @return the aggregateBw
	 */
	public long getAggregateBw() {
		return aggregateBw;
	}
	
	/**
	 * @return the src
	 */
	public Device getSrc() {
		return src;
	}

	/**
	 * @param src the src to set
	 */
	public void setSrc(Device src) {
		this.src = src;
	}

	/**
	 * @return the dst
	 */
	public Device getDst() {
		return dst;
	}

	/**
	 * @param dst the dst to set
	 */
	public void setDst(Device dst) {
		this.dst = dst;
	}

	
	// 
	// BW management functions
	// 

	/**
	 * Return true if aggregate bw is enough to accommodate this flow
	 * */
	public boolean canAccommodate(Flow f){
		return availableAggregateBw >= f.getBwReq();
	}
	
	/**
	 * Allocate bandwidth for flow f when it's added.
	 * @return the decision in <port,bw> pair
	 * */
	public List<PortBwTuple> allocateBw(Flow f){
		//TODO: bin-packing??
		//FIXME
		// NOTE: for simulation, we do NOT care about which
		// link accommodate this flow, 
		
		this.aggregateBw -= f.getBwReq();
		return null;
	}
	
	//
	// Inner classes
	//
	
	/**
	 * A simple <port,bw> tuple
	 * */
	public class PortBwTuple { 
		public final int port; 
		public final long bw; 
		public PortBwTuple(int port, long bw) { 
			this.port = port; 
		    this.bw = bw; 
		}
	} 
	
	public void addFlow(Flow f){
		//TODO: bookkeeping a flow
	}
	public void delFlow(Flow f){
		//TODO:bookkeeping a flow
	}
}
